package top.went.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.went.exception.InputException;
import top.went.exception.NotFoundException;
import top.went.exception.ServiceException;
import top.went.pojo.LogEntity;
import top.went.pojo.UserEntity;
import top.went.service.LogService;

import javax.servlet.http.HttpServletRequest;
import javax.sql.rowset.serial.SerialException;
import java.lang.reflect.Method;
import java.rmi.ServerException;
import java.sql.Date;

@Aspect
public class LogAopAction {
    @Autowired
    private LogService logService;

    @Pointcut("execution(* top.went.controller..*.*(..))")
    private void controllerAspect() {
    }

    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //常见日志实体对象
        LogEntity log = new LogEntity();
        //获取系统时间
        log.setLogOptionTime(new Date(System.currentTimeMillis()));
        //获取系统IP
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = getRemoteHost(request);
        log.setLogLoginIp(ip);
        //拦截的实体类
        Object target = pjp.getTarget();
        //拦截的方法名称
        String methodName = pjp.getSignature().getName();
        //拦截的方法参数
        Object[] args = pjp.getArgs();
        //拦截的方法参数类型
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)){
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        Object object = null;
        //获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName,parameterTypes);
        } catch (NoSuchMethodException e1){
            e1.printStackTrace();
        }/* catch (SerialException e1){
            e1.printStackTrace();
        }*/
        if (method !=null){
            //判断是否包含自定义注解
            if (method.isAnnotationPresent(SystemLog.class)){
                SystemLog systemLog = method.getAnnotation(SystemLog.class);
                log.setLogOptionType(systemLog.module());
                log.setLogOptionContent(systemLog.methods());
                try {
                    object = pjp.proceed();
                    log.setLogRemark("执行成功！");
                    //获取登录用户账户
                    UserEntity user = (UserEntity) request.getSession().getAttribute("user");
                    log.setTbUserByUserId(user);
                    System.out.println("成功："+log);
                    //生成日志数据记录
                    logService.addLog(log);
                }catch (NotFoundException | InputException | ServiceException e){
                    errorLogs(log,request);
                    throw e;
                } catch (Throwable e){
                    e.printStackTrace();
                    errorLogs(log, request);
                }
            }else {
                //没有包含注解
                object = pjp.proceed();
            }
        }else {
            //不需要拦截的直接执行
            object = pjp.proceed();
        }
        return object;
    }

    private void errorLogs(LogEntity log, HttpServletRequest request) throws ServiceException {
        log.setLogRemark("执行失败！");
        //获取登录用户账户
        UserEntity user = (UserEntity) request.getSession().getAttribute("user");
        log.setTbUserByUserId(user);
        System.out.println("失败："+log);
        logService.addLog(log);
    }

    /**
     * 获取远程客户端Ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
}
